ποΈGitΠ―ΡΠ°ποΈ
Node / meshtastic / Meshtastic-Android / files / specs / 20260521-153452-car-app-library-integration / quickstart.md
specs/20260521-153452-car-app-library-integration/quickstart.md bd2863243bab6eb213401d949839a2bc74dde7e2 (bd286324) Text, 5.15 KB
Quickstart: Car App Library Integration
Feature: Car App Library Integration
Date: 2026-05-21
Prerequisites
β’ Android Studio Ladybug or newer (for CAL preview tools)
β’ JDK 21 (T383838JAVA_HOME set)
β’ T383838ANDROID_HOME set with API 35+ SDK installed
β’ Proto submodule initialized: T383838git submodule update --init
β’ T383838local.properties configured: T383838cp secrets.defaults.properties local.properties
β’ Android Auto Desktop Head Unit (DHU) installed via SDK Manager β SDK Tools β Android Auto Desktop Head Unit
Setup
1. Sync and Build
T282828
T8b949e# Full sync (includes new :feature:car module)
./gradlew sync
T8b949e# Build google flavor (required β car module is google-only)
./gradlew assembleGoogleDebug
2. Install DHU for Testing
The Desktop Head Unit simulates Android Auto on your development machine.
T282828
T8b949e# Install via SDK Manager (or command line)
sdkmanager Ta5d6ff"extras;google;auto"
T8b949e# Start DHU (after connecting a device/emulator with the app installed)
Te6edf3$ANDROID_HOME/extras/google/auto/desktop-head-unit
3. Run on Android Auto (Projection Mode)
1. Install the google debug build on a physical device: T383838./gradlew installGoogleDebug
2. Enable Developer Mode in Android Auto settings on the phone
3. Start the DHU: T383838desktop-head-unit
4. The Meshtastic car app appears in the DHU's app launcher under "Messaging" category
4. Run on AAOS Emulator
T282828
T8b949e# Create AAOS emulator (API 33+ automotive system image)
avdmanager create avd -n Ta5d6ff"AAOS_Test" -k Ta5d6ff"system-images;android-33;google_apis_playstore;x86_64" --device Ta5d6ff"automotive_1024p_landscape"
T8b949e# Start emulator
emulator -avd AAOS_Test
T8b949e# Install
./gradlew installGoogleDebug
Development Workflow
Module Location
All car-specific code lives in T383838feature/car/:
T282828
feature/car/src/main/kotlin/org/meshtastic/feature/car/
βββ di/ β Koin DI module
βββ service/ β CarAppService + Session
βββ screens/ β CAL Screen implementations
βββ alerts/ β Emergency banner handler
βββ panels/ β Minimized Control Panel
βββ util/ β Helpers (Crashlytics tagger, template builders)
Key Development Patterns
Screen implementation:
T282828
Tff7b72class T56d364MessagingScreenTb4b4b4(Te6edf3carContextTb4b4b4: Te6edf3CarContextTb4b4b4) Tb4b4b4: Te6edf3ScreenTb4b4b4(Te6edf3carContextTb4b4b4) Tb4b4b4{
T8b949e// Inject repositories via Koin
Tff7b72private Tff7b72val Te6edf3packetRepositoryTb4b4b4: Te6edf3PacketRepository Tff7b72by Te6edf3injectTb4b4b4(Tb4b4b4)
Tff7b72override Tff7b72fun Td2a8ffonGetTemplateTb4b4b4(Tb4b4b4)Tb4b4b4: Te6edf3Template Tb4b4b4{
T8b949e// Build template from current state
T8b949e// Call invalidate() when data changes to trigger re-render
Tb4b4b4}
Tb4b4b4}
Data observation (CAL doesn't use Compose β use coroutine collection):
T282828
T8b949e// In Screen's lifecycle, collect flows and call invalidate()
Te6edf3lifecycleScopeTb4b4b4.Te6edf3launch Tb4b4b4{
Te6edf3repositoryTb4b4b4.Te6edf3getContactsTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3collect Tb4b4b4{ Te6edf3contacts Tff7b72-Tff7b72>
Te6edf3cachedContacts Tff7b72= Te6edf3contacts
Te6edf3invalidateTb4b4b4(Tb4b4b4) T8b949e// Triggers onGetTemplate() re-call
Tb4b4b4}
Tb4b4b4}
Template refresh: CAL screens are invalidated manually β no reactive binding. Call T383838invalidate() whenever backing data changes.
Testing
T282828
T8b949e# Unit tests (uses androidx.car.app:app-testing)
./gradlew :feature:car:testGoogleDebugUnitTest
T8b949e# Lint + formatting
./gradlew :feature:car:spotlessApply :feature:car:spotlessCheck :feature:car:detekt
Test approach: Use T383838SessionController and T383838TestCarContext from T383838app-testing artifact to simulate host interactions without a real car/DHU.
T282828
Tf0883e@Test
Tff7b72fun Td2a8ff`messaging screen shows conversations`Tb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3controller Tff7b72= Te6edf3SessionControllerTb4b4b4(
Te6edf3MeshtasticCarSessionTb4b4b4(Te6edf3testSessionInfoTb4b4b4)Tb4b4b4,
Te6edf3TestCarContextTb4b4b4(Te6edf3ApplicationProviderTb4b4b4.Te6edf3getApplicationContextTb4b4b4(Tb4b4b4)Tb4b4b4)
Tb4b4b4)
T8b949e// Push screen, assert template content
Tb4b4b4}
Debugging
β’ CAL Logcat filter: T383838tag:CarApp OR tag:CarService
β’ Template errors: CAL validates templates at runtime β check logcat for T383838TemplateValidationException
β’ Screen stack: Use T383838ScreenManager.getTop() to inspect current screen
β’ Crashlytics: Filter by T383838car_session custom key in Firebase Console
Common Tasks
βββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Task β Command / Action β
βββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Add a new screen β Create T383838Screen subclass in T383838screens/, register in navigation β
β Add a CAL dependency β Update T383838gradle/libs.versions.toml + T383838feature/car/build.gradle.kts β
β Test with DHU β T383838desktop-head-unit after installing google debug build β
β Check template compliance β Run app on DHU; host validates template constraints β
β Filter car crashes β Firebase Console β Crashlytics β Filter: T383838car_session is not empty β
β Full verification β T383838./gradlew spotlessApply :feature:car:spotlessCheck :feature:car:detβ¦ β
βββββββββββββββββββββββββββββ΄βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Architecture Notes
β’ No Compose: CAL uses its own template-based rendering. Don't mix Compose APIs.
β’ No T383838commonMain: This is an Android-only module. All code in T383838src/main/kotlin/.
β’ Shared BLE: Don't create new BLE connections. Inject existing T383838BleConnection singleton.
β’ Koin DI: All core repositories are already in the graph. Just T383838inject() them.
β’ Flavor: Only T383838google flavor includes this module. Never reference it from T383838fdroid code.
Served by rngit 1.5.4 - Generated in 0.05s